#include <iostream>
using namespace std;

#include <cstdlib>

#include "mem.hpp"

bool mem_bavard=false;

const int _maxi=10000;
int _imax=0;
void * _m_addr[_maxi];
size_t _m_taille[_maxi];
bool _m_cr[_maxi];

void erreur(const char * mesg) { 
  cerr << mesg << endl;
  exit(1);
}

const char * _op=0;
void bavarde(bool ajout, void * ptr, size_t s) {
  if (mem_bavard)
    cerr << _op << ": "
	 << ((ajout)?"alloc":"libér") << "ation de " << s
	 << " octets en " << ptr 
	 << " (total alloué : " << place_occupee() << ")\n";
  _op=0;
}

void * operator new(size_t size) {
  if (_imax>=_maxi) erreur("trop d'allocations simultanées.");
  void * ptr=malloc(size);
  if (ptr==NULL) erreur("memoire insuffisante.");
  _m_addr[_imax]=ptr;
  _m_taille[_imax]=size;
  if (!(_m_cr[_imax++]=(_op!=0))) _op="new";
  bavarde(true,ptr,size);
  return ptr;
}

void * operator new[](size_t size) {
  _op="new[]";
  return operator new(size);
}

void operator delete(void * ptr) {
  // delete [] ou delete sur un pointeur NULL => pas d'appel à cet opérateur !
  // if (ptr==NULL) erreur("libération d'une adresse NULL.");
  int i=0;
  while (i<_imax && _m_addr[i]!=ptr) i++;
  if (i==_imax) {
    cerr << ptr << " : ";
    erreur("delete sur une adresse non actuellement allouée par new.");
  }
  if (_m_cr[i]==(_op==0)) {
    cerr << ptr << " : ";
    if (_op==0) erreur("delete sur une adresse allouée par new[].");
    else erreur("delete[] sur une adresse allouée par new.");
  }
  size_t size=_m_taille[i];
  _m_addr[i]=_m_addr[--_imax];
  _m_taille[i]=_m_taille[_imax];
  _m_cr[i]=_m_cr[_imax];
  free(ptr);
  if (!_op) _op="delete";
  bavarde(false,ptr,size);
}

void operator delete[](void * ptr) { 
  _op="delete[]";
  operator delete(ptr);
}

size_t place_occupee() {
  size_t s=0;
  for (int i=0; i<_imax; i++) s+=_m_taille[i];
  return s;
}

void dirmem() { cout << "place occupée = " << place_occupee() << endl; }
